<template>
  <teleport to="body">
    <transition name="slide-bottom">
      <div
        v-if="type === FULLSCREEN_PHOTO_TYPE.SINGLE"
        class="img-full"
        :style="{ transform: `translateY(${closeLengthY}px)` }"
        ref="imgFull"
      >
        <img
          :src="dataUrl"
          alt="creator photo"
          ref="img"
          :style="imgTransformStyle"
          @transitionend="imgTransition = false"
        />
        <WaterMark v-if="showWaterMark"></WaterMark>
        <Icon class="close pointer" size="24" name="close" @click="close"></Icon>
      </div>
    </transition>
  </teleport>
</template>

<script setup>
import { computed, ref } from 'vue'
import { usePrevious, useSwipe } from '@vueuse/core'
import { storeToRefs } from 'pinia'
import { useFullscreenPhotoStore } from '@/store/fullscreen-photo'
import velocityCalculator from '@/utils/velocity-calculator'
import WaterMark from '@/components/common/WaterMark.vue'
import { useGesture } from '@/compositions/mobile/gesture'
import { usePreventTouchmove } from '@/compositions/mobile/preventTouchmove'
import { FULLSCREEN_PHOTO_TYPE } from '@/constant'

const imgFull = ref(null)
usePreventTouchmove(imgFull)

const fullscreenPhotoStore = useFullscreenPhotoStore()
const { type, dataUrl, showWaterMark } = storeToRefs(fullscreenPhotoStore)
const { closeFullscreen } = fullscreenPhotoStore

// 下滑關閉
const { abs, floor, max } = Math
const { reset: resetVelocity, updatePosition, getVelocity } = velocityCalculator()
const SWIPE_VELOCITY_THRESHOLD = 100
const closeStartY = ref(null)
const closeLengthY = computed(() => {
  if (closeStartY.value !== null) {
    return max(0, closeStartY.value - floor(lengthY.value))
  }
  return 0
})
const { lengthY } = useSwipe(imgFull, {
  onSwipe() {
    if (scaling.value) return

    const y = floor(lengthY.value)
    updatePosition(y)

    if (y < 0 && !scaleCenterY.value && closeStartY.value === null) {
      closeStartY.value = y
    }
  },
  onSwipeEnd() {
    if (closeStartY.value === null) return

    const y = floor(lengthY.value)
    const delta = y - floor(prevLengthY.value)

    const velocity = abs(getVelocity())
    resetVelocity()

    if (y < 0 && delta < 0 && (velocity > SWIPE_VELOCITY_THRESHOLD || closeLengthY.value > 100)) {
      close()
    }
    closeStartY.value = null
  },
})
const prevLengthY = usePrevious(lengthY)

// gesture
const img = ref(null)
const imgTransition = ref(false)
const { scale, scaling, scaleCenterX, scaleCenterY, reset } = useGesture(img, {
  onTap: () => (imgTransition.value = true),
})
const imgTransformStyle = computed(() => ({
  transition: imgTransition.value ? 'transform 0.3s ease-out' : '',
  transform: `scale(${scale.value})`,
  transformOrigin:
    scaleCenterX.value === null && scaleCenterY.value === null ? '' : `${scaleCenterX.value}px ${scaleCenterY.value}px`,
}))

function close() {
  closeFullscreen()
  reset()
}
</script>

<style lang="scss" scoped>
.slide-bottom-enter-from {
  opacity: 0;
}

.slide-bottom-enter-active {
  transition: opacity 0.3s ease-out;
}
.slide-bottom-leave-to {
  transform: translateY(100%) !important; // 沒用 !important 會被 inline transform 擋到
}
.slide-bottom-leave-active {
  transition: transform 0.3s ease-out;
}

.img-full {
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.6);
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1; // MediaWall.vue 當中的 tab sticky 時需要設定 z-index，會跟這邊衝突所以這邊也得設定至少同層級
  display: flex;
  justify-content: center;
  align-items: center;

  img {
    width: 100%;
    height: 100%;
    object-fit: contain;
  }

  .close {
    position: absolute;
    top: 1rem;
    right: 1rem;
  }
}
</style>
